﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design.Serialization;
using System.Linq;
using System.Text;
using System.Windows.Forms;


using Wicresoft.Shell.Core;
using System.Xml;
using System.ComponentModel.Design;
using UmcProvider;
using System.IO;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Collections;
using System.Drawing;
using System.Reflection;
using Wicresoft.Shell.Package.AppExp.ToolboxControl;
using System.Text.RegularExpressions;


namespace Wicresoft.Shell.Package.AppExp
{
    public class UmcDesignerLoader : BasicDesignerLoader, INameCreationService
    {        
        #region INameCreationService Members

        public string CreateName(IContainer container, Type dataType)
        {
            int i = 0;
            string name = dataType.Name;

            // Increment counter until we find a name that's not in use
            while (true)
            {
                ++i;
                if (container.Components[name + i] == null)
                {
                    break;
                }
            }

            string ret = name + i;
            return ret;
        }

        public bool IsValidName(string name)
        {
            return true;
        }

        public void ValidateName(string name)
        {
            //throw new NotImplementedException();
        }

        #endregion

        public IDesignerLoaderHost _host;
        private IComponent root = null;
        private XmlDocument xmlDocument;


        protected override void PerformFlush(IDesignerSerializationManager serializationManager)
        {
        }

        protected override void PerformLoad(IDesignerSerializationManager serializationManager)
        {
            //from IDesignerLoaderHost we can get IDesignerHost
            this._host = this.LoaderHost;
            if (this._host == null)
            {
                throw new ArgumentNullException("BasicHostLoader.BeginLoad: Invalid designerLoaderHost.");
            }
            //when design surface begin to load , this provide the first component which should be a root surface control
            //here we create a umcBody and named it UmcHost.
            root = _host.CreateComponent(typeof(UmcBody), "UmcHost");

            //IDesigner rootDesigner = _host.GetDesigner(_host.RootComponent);
            //TypeDescriptor.AddAttributes(rootDesigner, new Attribute[] 
            //{ new ToolboxItemFilterAttribute("Wicresoft.Shell.Package.AppExp.ToolboxControl", ToolboxItemFilterType.Require) });
            //TypeDescriptor.AddAttributes(rootDesigner, new Attribute[] 
            //{ new ToolboxItemFilterAttribute("System.Windows.Forms", ToolboxItemFilterType.Prevent) });

        }

        public override void Dispose()
        {
            if (root != null)
            {
                root.Dispose();
                root = null;
            }
            base.Dispose();
        }


        #region DeSerialize
        /// <summary>
        ///  Implement this method to generate design for current code
        /// </summary>
        /// <param name="code">source umc code</param>
        internal bool UpdateDesignerView(string code)
        {   
            XmlDocument xd = new XmlDocument();
            //pre deal the source
            code = PreDealFromCodeToDesign(code);
            try
            {
                //load behavior may be throw exception
                xd.LoadXml(code);
                IDesignerHost dh = GetService(typeof(IDesignerHost)) as IDesignerHost;
                new CodeDomLoader().DeSerialize(dh, xd);
                return true;
            }
            catch(Exception ex)
            {
                
                //Error(System.Xml.XmlException): '=' is an unexpected token. The expected token is ';'. Line 1, position 951.
                Logger.Output(string.Format("Error({0}):{1}",ex.GetType().FullName,ex.Message),WriteTo.OutputWindow);
                return false;
            }
        }

        /// <summary>
        /// predeal the source in ord to save the velocity script and some 
        /// elements that is not supported in the design view
        /// </summary>
        /// <param name="source"></param>
        /// <returns></returns>
        private string PreDealFromCodeToDesign(string source)
        {
            //add a root
            source = "<DOCUMENT_ELEMENT>" + source + "</DOCUMENT_ELEMENT>";
            string velocityDeclarationPattren = "^[ \t]*#.*";
            MatchCollection mc = Regex.Matches(source, velocityDeclarationPattren, RegexOptions.Multiline);
            List<string> HasMatched = new List<string>();
            foreach (Match m in mc)
            {
                //source = source.Insert(m.Index, "<Script>");
                //source = source.Insert(m.Index + m.Length + 8, "</Script>"); 
                if (HasMatched.Find(p => p == m.Value) == null)
                {
                    source = source.Replace(m.Value, "<Script>\n" + m.Value + "</Script>");
                    //Logger.Output(m.Value, WriteTo.OutputWindow);
                    HasMatched.Add(m.Value);
                    
                }
            }
            return source;
        }

        #endregion

        #region Serialize - Flush
        /// <summary>
        /// This will recussively go through all the objects in the tree and
        /// serialize them to Xml
        /// </summary>
        public void PerformFlushWorker()
        {
            IDesignerHost idh = (IDesignerHost)this._host.GetService(typeof(IDesignerHost));
            xmlDocument = new CodeDomLoader().Serialize(idh);
        }

        /// <summary>
        /// Implement this method to generate code for current design.
        /// </summary>
        /// <returns></returns>
        internal string GetCode()
        {
            PerformFlushWorker();
            StringWriter sw;
            sw = new StringWriter();
            XmlTextWriter xtw = new XmlTextWriter(sw);
            xtw.Formatting = Formatting.Indented;
            xmlDocument.WriteTo(xtw);
            //clean up the additional root which is added in the preoperation to the source code
            string cleanup = sw.ToString().Replace("<DOCUMENT_ELEMENT>", "");
            cleanup = cleanup.Replace("</DOCUMENT_ELEMENT>", "");
            //clean up the script node which is a kind of middle element
            cleanup = cleanup.Replace("<Script>", "").Replace("\r</Script>", "").Replace("</Script>", "");
            sw.Close();
            return cleanup;
        }

        #endregion

    }
}
